package com.wwj.server.notify;

import com.google.gson.Gson;
import com.wwj.core.wawa.entity.Player;
import com.wwj.core.wawa.service.IPlayerService;
import com.wwj.server.model.Message;
import com.wwj.server.notify.common.MsgConstants;
import com.wwj.server.notify.msg.*;
import com.wwj.server.notify.session.SessionImpl;
import com.wwj.server.notify.session.SessionManager;
import com.wwj.server.notify.utils.SpringContextUtils;
import com.wwj.server.session.Session;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.util.Iterator;
import java.util.LinkedHashSet;

/**
 * 消息接受处理类
 *
 * @author tysci
 */
public class ServerHandler extends SimpleChannelInboundHandler<Message> {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private IPlayerService playerService = (IPlayerService) SpringContextUtils.getContext().getBean("playerServiceImpl");

    //1.连接注册
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelRegistered(ctx);
        //logger.debug("host:{} 开始连接本机...", ((InetSocketAddress) ctx.channel().remoteAddress()).getHostName());
    }

    //2.连接激活
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        //logger.debug("host:{} 连接通道已激活...", ((InetSocketAddress) ctx.channel().remoteAddress()).getHostName());
    }


    /**
     * 接收消息
     */
    //3.数据读取
    @Override
    public void channelRead0(ChannelHandlerContext ctx, Message message) throws Exception {
        //消息分类
        //logger.debug("host:{} 开始接收消息...", ((InetSocketAddress) ctx.channel().remoteAddress()).getHostName());
        //logger.debug("消息内容：" + new String(message.getData()));
        handlerMessage(new SessionImpl(ctx.channel()), message);
    }

    //4.数据读取完毕
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
        //logger.debug("host:{} 消息接收完毕...", ((InetSocketAddress) ctx.channel().remoteAddress()).getHostName());
    }


    /**
     * 断线移除会话
     */
    //5.连接无效
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Session session = new SessionImpl(ctx.channel());
        Object object = session.getAttachment();
        if (object instanceof Player) {
            Player player = (Player) object;
            for (String key : Server.deviceMap.keySet()) {
                LinkedHashSet userSet = Server.deviceMap.get(key);
                if (userSet.contains(SessionManager.PREFIX_SESSION_KEY_USER + player.getId())) {
                    userSet.remove(SessionManager.PREFIX_SESSION_KEY_USER + player.getId());
                }
            }
            SessionManager.removeSession(SessionManager.PREFIX_SESSION_KEY_USER + player.getId());
            logger.debug("Player「id={}, nickname={}」 断开远程连接.", player.getId(), player.getNickname(), ((InetSocketAddress) ctx.channel().remoteAddress()).getHostName());
        }

    }

    //6.连接注销
    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        super.channelUnregistered(ctx);
        //logger.debug("host:{} 远程连接已注销...", ((InetSocketAddress) ctx.channel().remoteAddress()).getHostName());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        Channel channel = ctx.channel();
        if (!channel.isActive()) {
            logger.info("#######################--客户端-{}断开了长连接！", channel.remoteAddress());
            ctx.close();
        } else {
            ctx.fireExceptionCaught(cause);
            logger.error("#######################", cause);
        }
    }

    /**
     * 消息处理
     *
     * @param session
     * @param message
     */
    private void handlerMessage(Session session, Message message) {

        String sessionKey = null;
        LinkedHashSet<String> deviceSet = null;
        Player player = null;
        Iterator<String> it = null;
        switch (message.getType()) {
            //移动端用户连接
            case MsgConstants.USER_CONNECT:
                logger.debug("GET Message「Player」:" + new String(message.getData()));
                UserConnectMsg connectMsg = new Gson().fromJson(new String(message.getData()), UserConnectMsg.class);
                sessionKey = SessionManager.PREFIX_SESSION_KEY_USER + connectMsg.getUserId();
                if (connectMsg.getUserId() == null || "".equals(connectMsg.getUserId().trim())) {
                    UserConnectMsgAck connectMsgAck = new UserConnectMsgAck(connectMsg, "N");
                    SessionManager.sendMessage(session, connectMsgAck);
                    return;
                }
                player = playerService.findById(Integer.parseInt(connectMsg.getUserId()));
                if (null == player) {
                    UserConnectMsgAck connectMsgAck = new UserConnectMsgAck(connectMsg, "N");
                    SessionManager.sendMessage(session, connectMsgAck);
                    return;
                }
                if (SessionManager.isOnline(sessionKey)) {
                    SessionManager.replaceSession(sessionKey, session);
                    logger.debug("用户「user_id={},nickname={}」断线重连, sessionKey={}", player.getId(), player.getNickname(), sessionKey);
                } else {
                    if (SessionManager.putSession(sessionKey, session)) {
                        session.setAttachment(player);
                        UserConnectMsgAck connectMsgAck = new UserConnectMsgAck(connectMsg, "Y");
                        SessionManager.sendMessage(sessionKey, connectMsgAck);
                        logger.debug("用户「user_id={},nickname={}」建立连接, sessionKey={}", player.getId(), player.getNickname(), sessionKey);
                    }
                }
                break;
            case MsgConstants.USER_JOIN_ROOM:
                logger.debug("GET Message「Player」:" + new String(message.getData()));
                UserJoinRoomMsg userJoinRoomMsg = new Gson().fromJson(new String(message.getData()), UserJoinRoomMsg.class);
                sessionKey = SessionManager.PREFIX_SESSION_KEY_USER + userJoinRoomMsg.getUserId();
                if (!SessionManager.isOnline(sessionKey)) {
                    return;
                }

                deviceSet = Server.deviceMap.get(Server.PREFIX_DEVICE_MAP + userJoinRoomMsg.getDeviceId());
                if (null == deviceSet) {
                    deviceSet = new LinkedHashSet<>();
                    Server.deviceMap.put(Server.PREFIX_DEVICE_MAP + userJoinRoomMsg.getDeviceId(), deviceSet);
                }
                if (deviceSet.add(sessionKey)) {
                    UserJoinRoomMsgAck userJoinRoomMsgAck = new UserJoinRoomMsgAck(userJoinRoomMsg, "Y");
                    userJoinRoomMsgAck.setNum(Integer.toString(deviceSet.size()));
                    String[] tmpArr = deviceSet.toArray(new String[deviceSet.size()]);
                    if (tmpArr.length > 3) {
                        Player player1 = (Player) SessionManager.getSession(tmpArr[tmpArr.length - 1]).getAttachment();
                        Player player2 = (Player) SessionManager.getSession(tmpArr[tmpArr.length - 2]).getAttachment();
                        Player player3 = (Player) SessionManager.getSession(tmpArr[tmpArr.length - 3]).getAttachment();
                        userJoinRoomMsgAck.setLastThreeHeaderIcons(new String[]{player1.getHeaderIcon(), player2.getHeaderIcon(), player3.getHeaderIcon()});
                    } else {
                        String[] tmpIcons = new String[tmpArr.length];
                        int index = 0;
                        for (int i = tmpArr.length - 1; i >= 0; i--) {
                            Player playerX = (Player) SessionManager.getSession(tmpArr[i]).getAttachment();
                            tmpIcons[index] = playerX.getHeaderIcon();
                            index++;
                        }
                        userJoinRoomMsgAck.setLastThreeHeaderIcons(tmpIcons);
                    }
                    //注释掉，不用单独发给自己
                    //SessionManager.sendMessage(sessionKey, userJoinRoomMsgAck);

                    //发送进入房间弹幕
                    session = SessionManager.getSession(sessionKey);
                    player = (Player) session.getAttachment();
                    it = deviceSet.iterator();

                    while (it.hasNext()) {
                        String roomUserSessionKey = it.next();
                        if (SessionManager.isOnline(roomUserSessionKey)) {
                            //给所有人发送进入房间成功协议
                            SessionManager.sendMessage(roomUserSessionKey, userJoinRoomMsgAck);

                            DanmuMsgAck danmuMsgAck = new DanmuMsgAck(userJoinRoomMsg, player, player.getNickname() + "进入房间", "Y");
                            SessionManager.sendMessage(roomUserSessionKey, danmuMsgAck);
                        }
                    }
                }
                break;
            case MsgConstants.USER_LEAVE_ROOM:
                logger.debug("GET Message「Player」:" + new String(message.getData()));
                UserLeaveRoomMsg userLeaveRoomMsg = new Gson().fromJson(new String(message.getData()), UserLeaveRoomMsg.class);
                sessionKey = SessionManager.PREFIX_SESSION_KEY_USER + userLeaveRoomMsg.getUserId();
                if (!SessionManager.isOnline(sessionKey)) {
                    return;
                }
                deviceSet = Server.deviceMap.get(Server.PREFIX_DEVICE_MAP + userLeaveRoomMsg.getDeviceId());
                if (null == deviceSet) {
                    UserLeaveRoomMsgAck userLeaveRoomMsgAck = new UserLeaveRoomMsgAck(userLeaveRoomMsg, "N");
                    SessionManager.sendMessage(sessionKey, userLeaveRoomMsgAck);
                    return;
                } else {
                    if (deviceSet.contains(sessionKey)) {
                        if (deviceSet.remove(sessionKey)) {
                            UserLeaveRoomMsgAck userLeaveRoomMsgAck = new UserLeaveRoomMsgAck(userLeaveRoomMsg, "Y");
                            SessionManager.sendMessage(sessionKey, userLeaveRoomMsgAck);

                            userLeaveRoomMsgAck.setNum(Integer.toString(deviceSet.size()));
                            String[] tmpArr = deviceSet.toArray(new String[deviceSet.size()]);
                            if (tmpArr.length > 3) {
                                Player player1 = (Player) SessionManager.getSession(tmpArr[tmpArr.length - 1]).getAttachment();
                                Player player2 = (Player) SessionManager.getSession(tmpArr[tmpArr.length - 2]).getAttachment();
                                Player player3 = (Player) SessionManager.getSession(tmpArr[tmpArr.length - 3]).getAttachment();
                                userLeaveRoomMsgAck.setLastThreeHeaderIcons(new String[]{player1.getHeaderIcon(), player2.getHeaderIcon(), player3.getHeaderIcon()});
                            } else {
                                String[] tmpIcons = new String[tmpArr.length];
                                int index = 0;
                                for (int i = tmpArr.length - 1; i >= 0; i--) {
                                    Player playerX = (Player) SessionManager.getSession(tmpArr[i]).getAttachment();
                                    tmpIcons[index] = playerX.getHeaderIcon();
                                    index++;
                                }
                                userLeaveRoomMsgAck.setLastThreeHeaderIcons(tmpIcons);
                            }

                            session = SessionManager.getSession(sessionKey);
                            player = (Player) session.getAttachment();
                            it = deviceSet.iterator();
                            while (it.hasNext()) {
                                String roomUserSessionKey = it.next();
                                if (SessionManager.isOnline(roomUserSessionKey)) {
                                    //给所有人发送离开房间协议
                                    SessionManager.sendMessage(roomUserSessionKey, userLeaveRoomMsgAck);

                                    DanmuMsgAck danmuMsgAck = new DanmuMsgAck(userLeaveRoomMsg, player, player.getNickname() + "离开房间", "Y");
                                    SessionManager.sendMessage(roomUserSessionKey, danmuMsgAck);
                                }
                            }
                            return;
                        }
                    }
                    UserLeaveRoomMsgAck userLeaveRoomMsgAck = new UserLeaveRoomMsgAck(userLeaveRoomMsg, "N");
                    SessionManager.sendMessage(sessionKey, userLeaveRoomMsgAck);
                }
                break;
            case MsgConstants.USER_HEARTBEAT:
                UserHeartbeatMsg userHeartbeatMsg = new Gson().fromJson(new String(message.getData()), UserHeartbeatMsg.class);
                sessionKey = SessionManager.PREFIX_SESSION_KEY_USER + userHeartbeatMsg.getUserId();
                SessionManager.sendMessage(sessionKey, new UserHeartbeatMsgAck(userHeartbeatMsg));
                break;
            case MsgConstants.DAN_MU:
                logger.debug("GET Message「Player」:" + new String(message.getData()));
                DanmuMsg danmuMsg = new Gson().fromJson(new String(message.getData()), DanmuMsg.class);
                deviceSet = Server.deviceMap.get(Server.PREFIX_DEVICE_MAP + danmuMsg.getDeviceId());
                sessionKey = SessionManager.PREFIX_SESSION_KEY_USER + danmuMsg.getUserId();
                if (null == deviceSet) {
                    DanmuMsgAck danmuMsgAck = new DanmuMsgAck(danmuMsg, "N");
                    SessionManager.sendMessage(sessionKey, danmuMsgAck);
                    return;
                }
                it = deviceSet.iterator();
                player = (Player) session.getAttachment();
                while (it.hasNext()) {
                    String roomUserSessionKey = it.next();
                    if (SessionManager.isOnline(roomUserSessionKey)) {
                        DanmuMsgAck danmuMsgAck = new DanmuMsgAck(danmuMsg, player, "Y");
                        SessionManager.sendMessage(roomUserSessionKey, danmuMsgAck);
                    }
                }
                break;
            default:
                break;
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            switch (e.state()) {
                case READER_IDLE:
                    handleReaderIdle(ctx);
                    break;
                case WRITER_IDLE:
                    handleWriterIdle(ctx);
                    break;
                case ALL_IDLE:
                    handleAllIdle(ctx);
                    break;
                default:
                    break;
            }
        }
    }

    protected void handleReaderIdle(ChannelHandlerContext ctx) {
        Session session = new SessionImpl(ctx.channel());
        if (null != session.getAttachment() && session.getAttachment() instanceof Player) {
            Player player = (Player) session.getAttachment();
            logger.debug("Player「id={}, nickname={}」 超时，清除session信息", player.getId(), player.getNickname(), ((InetSocketAddress) ctx.channel().remoteAddress()).getHostName());
        }
        ctx.close();
    }

    protected void handleWriterIdle(ChannelHandlerContext ctx) {
        System.err.println("---WRITER_IDLE---");
    }

    protected void handleAllIdle(ChannelHandlerContext ctx) {
        System.err.println("---ALL_IDLE---");
    }
}